/*=========================================================================
 * Copyright (c) 2010-2011 VMware, Inc. All rights reserved.
 * This product is protected by U.S. and international copyright
 * and intellectual property laws. VMware products are covered by
 * one or more patents listed at http://www.vmware.com/go/patents.
 *=========================================================================
 */
package com.gemfire.onlineretailer.ui;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

import com.gemstone.gemfire.cache.query.FunctionDomainException;
import com.gemstone.gemfire.cache.query.NameResolutionException;
import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
import com.gemstone.gemfire.cache.query.QueryService;
import com.gemstone.gemfire.cache.query.SelectResults;
import com.gemstone.gemfire.cache.query.TypeMismatchException;
import com.springsource.gemfire.training.accounts.payable.dao.AccountPayableGemfireDAO;
import com.springsource.gemfire.training.accounts.payable.domain.finance.AccountHeads;
import com.springsource.gemfire.training.accounts.payable.domain.finance.PaymentVoucher;
import com.springsource.gemfire.training.accounts.payable.domain.finance.PaymentVoucherType;
import com.springsource.gemfire.training.accounts.payable.domain.materials.Item;

/**
 * A command line user interface that prepares payments and then posts them to the cache. 
 * 
 * The supported commands are:
 * <ul>
 * <li>vendor
 * <li>employee
 * <li>misc
 * <li>quit
 * </ul>
 * 
 * @author GemStone Systems, Inc.
 * @author Binit Datta
 */
public class AccountsPayableCommandLineUI {
	private final OnlineRetailerDAO dao;
	private final BufferedReader in;
	private final PrintStream out;
    Random randomGenerator = new Random();

	public AccountsPayableCommandLineUI(OnlineRetailerDAO dao,
			InputStream in, PrintStream out) {
		this.dao = dao;
		this.in = new BufferedReader(new InputStreamReader(in));
		this.out = out;
	}

	/**
	 * Loop, reading commands from the input and processing them, until an exit
	 * command is received.
	 */
	public void processPayments() throws IOException {
		boolean keepRunning = true;

		usage();

		while (keepRunning) {
			System.out.print("> ");
			out.flush();
			String line = in.readLine();
			if (line == null) {
				break;
			}

			keepRunning = processPayment(line);
		}
	}

	/**
	 * Process a single line of input
	 * 
	 * @param line
	 *            the line to process.
	 * @return true if we should keep reading more commands, false if we should
	 *         stop
	 */
	private boolean processPayment(String line) throws IOException {
		Scanner scanner = new Scanner(line);

		if (readCommand(scanner, "vendor")) {

			prepareVendorPayment();
		}

		else if (readCommand(scanner, "employee")) {
			prepareEmployeePayment();

		}

		else if (readCommand(scanner, "misc")) {

			prepareMiscPartyPayment();

		}

		else if (readCommand(scanner, "exit|quit|q")) {
			return false;
		} else {
			usage();
		}

		return true;
	}

	private void prepareVendorPayment() throws IOException {
		Date currentDate = new Date();

		PaymentVoucher vendorPaymentVoucher = new PaymentVoucher();
	      int randomInt = randomGenerator.nextInt(100);

		vendorPaymentVoucher.setVoucherNo("VP/2013/"+randomInt);
		vendorPaymentVoucher.setDebitTheReceiver(dao
				.getAccountHead(AccountHeads.ACCOUNT_HEAD_1_CODE));
		vendorPaymentVoucher.setCreditTheGiver(dao
				.getAccountHead(AccountHeads.ACCOUNT_HEAD_2_CODE));
		vendorPaymentVoucher
				.setPaymentVoucherType(PaymentVoucherType.VENDOR_PAYMENT
						.getCode());
		vendorPaymentVoucher.setAmount(12000d);
		vendorPaymentVoucher.setUserId(dao.getEmployee("10001"));
		vendorPaymentVoucher.setTimeStamp(currentDate);

		dao.addPaymentVoucher(vendorPaymentVoucher.getVoucherNo(),
				vendorPaymentVoucher);
		
		pressEnterToContinue();
	}

	private void prepareEmployeePayment() throws IOException {

		Date currentDate = new Date();

		System.out.println("Entered employee");
		   int randomInt = randomGenerator.nextInt(100);
		PaymentVoucher employeePaymentVoucher = new PaymentVoucher();
		employeePaymentVoucher.setVoucherNo("EP/2013/"+randomInt);

		System.out.println("Accunt Code :"
				+ dao.getAccountHead(AccountHeads.ACCOUNT_HEAD_3_CODE));

		employeePaymentVoucher.setDebitTheReceiver(dao
				.getAccountHead(AccountHeads.ACCOUNT_HEAD_3_CODE));
		employeePaymentVoucher.setCreditTheGiver(dao
				.getAccountHead(AccountHeads.ACCOUNT_HEAD_4_CODE));
		employeePaymentVoucher
				.setPaymentVoucherType(PaymentVoucherType.EMPLOYEE_PAYMENT
						.getCode());
		employeePaymentVoucher.setAmount(12000d);
		employeePaymentVoucher.setUserId(dao.getEmployee("10001"));
		employeePaymentVoucher.setTimeStamp(currentDate);

		dao.addPaymentVoucher(employeePaymentVoucher.getVoucherNo(),
				employeePaymentVoucher);
		
		pressEnterToContinue();
	}

	private void prepareMiscPartyPayment() throws IOException {
		Date currentDate = new Date();
		System.out.println("Entered Misc");
		   int randomInt = randomGenerator.nextInt(100);

		PaymentVoucher miscPaymentVoucher = new PaymentVoucher();
		miscPaymentVoucher.setVoucherNo("MP/2013/"+randomInt);

		miscPaymentVoucher.setDebitTheReceiver(dao
				.getAccountHead(AccountHeads.ACCOUNT_HEAD_3_CODE));
		miscPaymentVoucher.setCreditTheGiver(dao
				.getAccountHead(AccountHeads.ACCOUNT_HEAD_4_CODE));
		miscPaymentVoucher
				.setPaymentVoucherType(PaymentVoucherType.MISC_PAYMENT
						.getCode());
		miscPaymentVoucher.setAmount(12000d);
		miscPaymentVoucher.setUserId(dao.getEmployee("10001"));
		miscPaymentVoucher.setTimeStamp(currentDate);

		dao.addPaymentVoucher(miscPaymentVoucher.getVoucherNo(),
				miscPaymentVoucher);
		
		pressEnterToContinue();
	}

	public void queryItems() throws FunctionDomainException,
			TypeMismatchException, NameResolutionException,
			QueryInvocationTargetException {
		Object result = dao.queryItems();
		System.out.println("Query result:\n\t" + formatQueryResult(result));
	}

	public void queryRawMaterialsItem() throws FunctionDomainException,
			TypeMismatchException, NameResolutionException,
			QueryInvocationTargetException {
		Object result = dao.queryRawMaterialItems();
		System.out.println("Query result:\n\t" + formatQueryResult(result));
	}

	public void queryPaymentVouchers() throws FunctionDomainException,
			TypeMismatchException, NameResolutionException,
			QueryInvocationTargetException {
		Object result = dao.queryPaymentVouchers();
		System.out.println("Query result:\n\t" + formatQueryResult(result));
	}

	public void queryAccountHeads() throws FunctionDomainException,
			TypeMismatchException, NameResolutionException,
			QueryInvocationTargetException {
		Object result = dao.queryAccountHeads();
		System.out.println("Query result:\n\t" + formatQueryResult(result));
	}

	public void executeItemFunction()  {
		
		Item item = null;
		try {
			List items = dao.executeItemFunction();

			for (Object itm : items){
				item = (Item) itm;
				System.out.println("Item Code :"+item.getItemCode());
				System.out.println("Item Code :"+item.getItemName());

			}
		}
		catch(Exception e){
			System.out.println("Exception :"+e.getMessage());
		}
	
	}
	public static String formatQueryResult(Object result) {
		if (result == null) {
			return "null";
		} else if (result == QueryService.UNDEFINED) {
			return "UNDEFINED";
		}
		if (result instanceof SelectResults) {
			Collection<?> collection = ((SelectResults<?>) result).asList();
			StringBuffer sb = new StringBuffer();
			for (Object e : collection) {
				sb.append(e + "\n\t");
			}
			return sb.toString();
		} else {
			return result.toString();
		}
	}

	/**
	 * Display a usage message.
	 */
	private void usage() {
		out.println("Commands:");
		out.println("vendor / employee / misc ...");
		out.println("     Prepare either a Vendor / Employee / Misc Payment voucher and persists that to the Cache region.");
		out.println("     list - List all Payment Voucher.");
		out.println("getemp empid - Get an Employee and displayes it");
		out.println("quit");
		out.println("     Exit the shell.");
	}


	/**
	 * Check to see if the given command is available in the input, and if so,
	 * read it from the scanner.
	 */
	private boolean readCommand(Scanner scanner, String command) {
		if (scanner.hasNext(command)) {
			scanner.next(command);
			return true;
		}
		return false;
	}
	
	private void pressEnterToContinue() throws IOException {
		System.out.println("Press Enter to continue.");
		in.readLine();
	}

}
